home *** CD-ROM | disk | FTP | other *** search
/ Total Java Scripts / Total Java Scripts.iso / JavaApplets / messages / circlebanner / CircleBanner.java < prev    next >
Encoding:
Java Source  |  1998-10-31  |  23.7 KB  |  732 lines

  1. /**
  2.   * @(#)CircleBanner.java
  3.   * Version : 1.0 06/03/98.
  4.   * Copyright (c) 1998 Michael Raillard. All Rights Reserved.
  5.   * @Author : Michael Raillard
  6.   * E-mail : raillard@arn.net
  7.   *
  8.   * Extends : java.applet.Applet.
  9.   * Purpose : Draws a rotating circular banner.
  10.   *
  11.   */
  12.  
  13. import java.awt.*;
  14. import java.applet.*;
  15. import java.awt.event.*;
  16. import java.net.*; 
  17. import java.util.Random;
  18. import java.util.Vector;
  19.  
  20.  
  21. public class CircleBanner extends Applet implements Runnable {
  22.     
  23.     private static int PARAM_message = 0;
  24.     private static int PARAM_direction = 1;
  25.     private static int PARAM_url = 2;
  26.     private static int PARAM_fontName = 3;
  27.     private static int PARAM_fontSize = 4;
  28.     private static int PARAM_fontStyle = 5;
  29.     private static int PARAM_fontPadding = 6;
  30.     private static int PARAM_background = 7;
  31.     private static int PARAM_foreground = 8;
  32.     private static int PARAM_image = 9;
  33.     private static int PARAM_imageAttribute = 10;
  34.     private static int PARAM_charEffects = 11;
  35.     private static int PARAM_seed = 12;
  36.     private static int PARAM_pause = 13;
  37.     private static int PARAM_rotationfactor = 14;
  38.     private static int PARAM_radius = 15;
  39.     private static int PARAM_x = 16;
  40.     private static int PARAM_y = 17;
  41.     private static double RAD = 180.0 / Math.PI;
  42.     
  43.     private boolean random, fixed, clockwise,
  44.                     center, tile, scale, loaded;
  45.     private double rotationfactor;
  46.     private int pause, message_beg, increment, cH,
  47.                 fontSize, fontStyle, randCount, fontPadding, 
  48.                 parm_radius, parm_x, parm_y, parm_seed,  
  49.                 imageWidth, imageHeight, 
  50.                 centered_XCorner, centered_YCorner;
  51.     private int[] mX;
  52.     
  53.     private Color background, foreground;               
  54.     private Color[] randColors; 
  55.     private Dimension appletSize;                     
  56.     private FontMetrics fm;
  57.     private Frame browserFrame;
  58.     private Graphics bufferGraphics;
  59.     private Image buffer, image;
  60.     private MediaTracker tracker;
  61.     private Rectangle[] rectangles;
  62.     private String message, fontName, imageName; 
  63.     private String[] m;
  64.     private Thread animator;
  65.     private URL url;
  66.         
  67.     //array stores HTML Applet Tag param name, and a default
  68.     public String[][] p = {
  69.         {"message","CircleBanner"},
  70.         {"direction","counterclockwise"},
  71.         {"url",""},
  72.         {"fontname","Helvetica"},
  73.         {"fontsize","12"},
  74.         {"fontstyle","plain"},
  75.         {"fontpadding","0"},
  76.         {"background","000000"},
  77.         {"foreground","FFFFFF"},
  78.         {"image",""},
  79.         {"imageattribute",""},
  80.         {"effects",""},
  81.         {"seed",""},
  82.         {"pause","100"},
  83.         {"rotationfactor", "100"},
  84.         {"radius",""},
  85.         {"x",""},
  86.         {"y",""},
  87.     };
  88.     
  89.     public void init()
  90.     {
  91.         setLayout(null);
  92.         appletSize = this.size();    
  93.         
  94.         try { browserFrame = (Frame) getParent(); }
  95.         catch(Exception e) { browserFrame = null; }
  96.         
  97.         //get parameters from HTML doc
  98.         getParameters();
  99.         
  100.         //initiate offscreen buffer.... 
  101.         buffer = this.createImage(appletSize.width, appletSize.height);
  102.         setBufferGraphics();
  103.         
  104.         //dimension of area to hold a character of this font....
  105.         Dimension fontSpaceDim = new Dimension(
  106.             (fm.getMaxAdvance() + 2 * fm.getLeading()) + fontPadding,
  107.             (fm.getMaxAscent() + fm.getMaxDescent() + 2 * fm.getLeading()) + fontPadding );
  108.         int fontSpace = (fontSpaceDim.width > fontSpaceDim.height) ? fontSpaceDim.width : fontSpaceDim.height;
  109.         
  110.         //determine properties of circle....
  111.         int cX, cY, minR, maxR;
  112.         double r;
  113.         int square = (appletSize.width > appletSize.height) ? 
  114.             appletSize.height : appletSize.width;               
  115.         cX = cY = square/2;                               //default center
  116.         
  117.         if(parm_x != -1000000) {cX = parm_x;} 
  118.         if(parm_y != -1000000) {cY = parm_y;}
  119.         
  120.         //determine radius....
  121.         r = (double) (cX - ((square/4)/2));               //default radius
  122.         if (parm_radius > -1) r = (double)parm_radius;
  123.  
  124.         //plot the the Cartesian co-ordinates of a circle that will fit in the applet....
  125.         Vector c = CirclePoints.circle(cX, cY, r, 1);
  126.         
  127.         //do math....
  128.         double angle = (Math.atan2((double) fontSpace, (double) r)) * RAD;
  129.         double num_m_rect = 360.00 / angle;
  130.         double anim_angle = (Math.atan2(((double) fontSpace) * rotationfactor, (double) r)) * RAD;
  131.         double num_anim_rect = 360.00 / anim_angle;
  132.         double anim_IncValue = ((double) c.size()/num_anim_rect);
  133.         if (anim_IncValue < 1) anim_IncValue = 1.00;
  134.         
  135.         if (rotationfactor > 1.00) num_m_rect = num_anim_rect;
  136.         
  137.         //create an array of rectangles, where chars will be placed....  
  138.         double dw = (double)fontSpaceDim.width + fm.getLeading();
  139.         double dh = (double)fontSpaceDim.height;
  140.         
  141.         Rectangle[] rec = new Rectangle[c.size()];
  142.         int prevX = (int)Math.rint(((DoublePoint)c.lastElement()).x - dw/2.00);
  143.         int prevY = (int)Math.rint(((DoublePoint)c.lastElement()).y - dh/2.00);
  144.         int nextX, nextY;
  145.         int j = -1;
  146.         double node = anim_IncValue;
  147.         
  148.         for (int i = 0; ((int)node) < c.size(); node += anim_IncValue){               
  149.             if ((i = (int) Math.rint(node)) >= c.size()) break;  
  150.         
  151.             nextX = (int)Math.rint(((DoublePoint)c.elementAt(i)).x - dw/2.00);
  152.             nextY = (int)Math.rint(((DoublePoint)c.elementAt(i)).y - dh/2.00);
  153.             if (nextX != prevX || nextY != prevY) {
  154.                 rec[++j] = new Rectangle(nextX, nextY, (int)dw, (int)dh);
  155.                 prevX = nextX;
  156.                 prevY = nextY;
  157.             }
  158.         }
  159.         System.arraycopy(rec, 0, rectangles = new Rectangle[j+1], 0, j+1);
  160.         increment = rectangles.length /(int)num_m_rect;
  161.         
  162.         //create arrays to hold the characters of the message & their x positions....
  163.         if(message.length() > (int)num_m_rect) message = message.substring(0, (int)num_m_rect);
  164.         
  165.         message_beg = clockwise ? 0 : (message.length() * increment) - increment;   
  166.         
  167.         m = new String[message.length()];
  168.         mX = new int[m.length];
  169.         
  170.         int maxascent = fm.getMaxAscent();
  171.         cH = (fontSpaceDim.height - (maxascent + fm.getMaxDescent() + fm.getLeading()))/2 + maxascent;
  172.         char[] mC = message.toCharArray();
  173.         for (int i = 0; i < message.length(); i++) {
  174.             m[i] = new String(mC,i,1);
  175.             mX[i]= (fontSpaceDim.width - fm.charWidth(message.charAt(i)))/2;
  176.         }
  177.         
  178.         //color effects for characters....
  179.         if (!p[PARAM_charEffects][1].equals("")) buildColorArray();
  180.  
  181.         //special handling for images....
  182.         if(!imageName.equals("")) {
  183.             tracker = new MediaTracker(this);
  184.             image = this.getImage(this.getDocumentBase(), imageName);
  185.             tracker.addImage(image, 0);
  186.             loaded = false;
  187.         }
  188.         else {
  189.             image = null;
  190.             loaded = false;
  191.         }
  192.         if(image != null) {
  193.             if (!loaded) {
  194.                 try {
  195.                     tracker.waitForID(0);
  196.                 }
  197.                 catch (InterruptedException e) {;}
  198.                 if(tracker.isErrorID(0)) {
  199.                     this.showStatus("Error loading image " + imageName + ", quitting.");
  200.                     return;
  201.                 }
  202.                 else loaded = true;
  203.                 while((imageWidth = image.getWidth(this)) < 0)
  204.                     try {Thread.sleep(100);}catch(InterruptedException e) {}
  205.                 while((imageHeight = image.getHeight(this)) < 0)
  206.                     try {Thread.sleep(100);}catch(InterruptedException e) {}
  207.                 
  208.                 if (center ) {
  209.                     centered_XCorner = appletSize.width/2 - imageWidth/2;
  210.                     if (centered_XCorner < 0) centered_XCorner = 0;
  211.                     centered_YCorner = appletSize.height/2 - imageHeight/2;
  212.                     if (centered_YCorner < 0) centered_YCorner = 0;
  213.                 }
  214.             }
  215.         }
  216.     }
  217.     
  218.     private void setBufferGraphics(){
  219.         bufferGraphics = buffer.getGraphics();
  220.         fm = bufferGraphics.getFontMetrics(new Font(fontName, fontStyle, fontSize));
  221.         bufferGraphics.setFont(fm.getFont());
  222.         bufferGraphics.setColor(background);
  223.         bufferGraphics.fillRect(0,0,appletSize.width,appletSize.height);
  224.     }
  225.     
  226.     public void destroy() {}
  227.     
  228.     public void update(Graphics g){ 
  229.         if (image != null) {
  230.                if (scale) {
  231.                 bufferGraphics.drawImage(image,
  232.                         0,0,appletSize.width,appletSize.height,0,0,100,100,this);
  233.             }
  234.             else if (tile) {
  235.                 for(int x = 0; x < appletSize.width; x += imageWidth)
  236.                     for(int y = 0; y < appletSize.height; y += imageHeight)
  237.                         bufferGraphics.drawImage(image, x, y, this);
  238.             }
  239.             else if (center) {
  240.                 bufferGraphics.setColor(background);
  241.                 bufferGraphics.fillRect(0,0,appletSize.width,appletSize.height);
  242.                 
  243.                 bufferGraphics.drawImage(image, centered_XCorner, centered_YCorner, this);
  244.             }
  245.             else {
  246.                 bufferGraphics.setColor(background);
  247.                 bufferGraphics.fillRect(0,0,appletSize.width,appletSize.height);
  248.                 
  249.                 bufferGraphics.drawImage(image, 0, 0, this);
  250.             }
  251.         }
  252.         else {
  253.             bufferGraphics.setColor(background);
  254.             bufferGraphics.fillRect(0,0,appletSize.width,appletSize.height);
  255.         }
  256.             
  257.         if (!random || !fixed) bufferGraphics.setColor(foreground);
  258.         
  259.            if (clockwise) {
  260.             for(int i = 0, j = message_beg; i < m.length; i++, j += increment) {
  261.                 int k = ( j >= rectangles.length) ? (j - rectangles.length) : j ;
  262.                 if (random) {
  263.                     bufferGraphics.setColor(randColors[randCount]);
  264.                     if (randCount < randColors.length - 1) randCount++; else randCount = 0;
  265.                 }
  266.                 if (fixed) bufferGraphics.setColor(randColors[i]);
  267.                 
  268.                 bufferGraphics.drawString(m[i], 
  269.                             rectangles[k].x + mX[i],
  270.                             rectangles[k].y + cH); 
  271.             }
  272.             message_beg = (message_beg + 1 >= rectangles.length) ? 0 : message_beg + 1;
  273.         }
  274.         else {
  275.             for(int i = ((message.length()) - 1), j = message_beg; 
  276.                          i > -1; i--, j -= increment) {
  277.                 int k = ( j < 0) ? (j + rectangles.length) : j ;
  278.                 if (random) {
  279.                     bufferGraphics.setColor(randColors[randCount]);
  280.                     if (randCount < randColors.length - 1) randCount++; else randCount = 0;
  281.                 }
  282.                 if (fixed) bufferGraphics.setColor(randColors[i]);
  283.                 
  284.                 bufferGraphics.drawString(m[i], 
  285.                             rectangles[k].x + mX[i],
  286.                             rectangles[k].y + cH); 
  287.             }
  288.             message_beg = (message_beg - 1 < 0) ? rectangles.length - 1: message_beg - 1;
  289.         }
  290.         paint(g); 
  291.     }
  292.     
  293.     public void paint(Graphics g){
  294.         g.drawImage(buffer, 0, 0, this);
  295.         g.dispose();
  296.     }
  297.     
  298.     public void start(){
  299.         if(animator == null) {
  300.             Thread current = Thread.currentThread();
  301.             current.setPriority(current.MIN_PRIORITY + 1);
  302.             animator = new Thread(this);
  303.             animator.setPriority(animator.MIN_PRIORITY);
  304.             animator.start();
  305.         }
  306.     }
  307.     
  308.     public void stop() {
  309.         if(animator != null) {
  310.             animator.stop();
  311.             animator = null;
  312.         }
  313.     }
  314.     
  315.     public void run(){
  316.         while(animator != null) {
  317.             repaint();
  318.             try {Thread.sleep(pause);} catch (InterruptedException e) { ; }
  319.         }
  320.     }
  321.     
  322.     public boolean mouseDown(java.awt.Event evt, int x, int y) {
  323.         try {
  324.             if(url != null)
  325.                 getAppletContext().showDocument(url);
  326.         }
  327.         catch(Exception e) {}
  328.         finally {return true;}
  329.     }
  330.  
  331.     public boolean mouseEnter(java.awt.Event evt, int x, int y) {
  332.         if (p[PARAM_url][1] != null &&
  333.            !p[PARAM_url][1].equals("")) {
  334.             showStatus(p[PARAM_url][1]);
  335.             if (browserFrame != null)
  336.                 browserFrame.setCursor(Frame.HAND_CURSOR);
  337.         }
  338.         return true;
  339.     }
  340.     
  341.     public boolean mouseExit(java.awt.Event evt, int x, int y) {
  342.         showStatus("");
  343.         return true;
  344.     }
  345.     
  346.     private void buildColorArray(){
  347.         double r;
  348.         Color[] colors = {Color.black, Color.blue, Color.cyan, Color.green,
  349.                           Color.lightGray, Color.magenta, Color.orange, Color.pink,
  350.                           Color.red, Color.white, Color.yellow};
  351.         
  352.         randCount = 0;
  353.         boolean seed, pastel;
  354.         seed = pastel = random = fixed = false;
  355.         Random ran;
  356.         
  357.         String effect = p[PARAM_charEffects][1].toUpperCase();
  358.         
  359.         if (effect.equals("RANDOMPASTELS")) {
  360.             random = true;
  361.             pastel = true;
  362.         }
  363.         else if (effect.equals("RANDOMCOLORS")) {
  364.             random = true;
  365.         }
  366.         else if (effect.equals("FIXEDPASTELS")) {
  367.             fixed = true;
  368.             pastel = true;
  369.         }
  370.         else if (effect.equals("FIXEDCOLORS")) {
  371.             fixed = true;
  372.         }
  373.             
  374.         randColors = new Color[random ? 100 : m.length];
  375.         if (seed = (parm_seed == -1000000) ? false : true ) ran = new Random((long)parm_seed);
  376.         else ran = null;
  377.         
  378.         if (pastel) 
  379.             for(int i = 0; i < randColors.length; i++) {
  380.                 r = (seed ? ran.nextDouble() : Math.random());
  381.                 randColors[i] = 
  382.                     Color.getHSBColor((float) r,
  383.                                       (float) 0.3,
  384.                                       (float) 0.99);
  385.             }
  386.         else 
  387.             for(int i = 0; i < randColors.length; i++)
  388.                 do {
  389.                 r = seed ? ran.nextDouble() : Math.random(); 
  390.                 randColors[i] = colors[((int) Math.ceil(r * 11))- 1];
  391.                 } while (randColors[i] == background);
  392.     }
  393.     
  394.     private void getParameters(){
  395.         
  396.         String param;
  397.         
  398.         for(int i = 0; i < p.length; i++) {
  399.             param = getParameter(p[i][0]);
  400.             if (param != null) 
  401.                 p[i][1] = param;
  402.         }
  403.         
  404.         message = p[PARAM_message][1];
  405.         imageName = p[PARAM_image][1];
  406.         fontName = p[PARAM_fontName][1];
  407.         
  408.         String[] fonts = Toolkit.getDefaultToolkit().getFontList();
  409.         for(int i = 0; i < fonts.length; i++) {
  410.             if (p[PARAM_fontName][1].equalsIgnoreCase(fonts[i])){
  411.                 fontName = fonts[i];
  412.                 break;
  413.             }
  414.         }
  415.         
  416.         if (p[PARAM_fontStyle][1].equalsIgnoreCase("PLAIN")){
  417.             fontStyle = Font.PLAIN;
  418.         }
  419.         else if (p[PARAM_fontStyle][1].equalsIgnoreCase("BOLD")){
  420.             fontStyle = Font.BOLD;
  421.         }
  422.         else if (p[PARAM_fontStyle][1].equalsIgnoreCase("ITALIC")){
  423.             fontStyle = Font.ITALIC;
  424.         }
  425.         else
  426.             fontStyle = Font.PLAIN;
  427.         
  428.         fontSize = parse(p[PARAM_fontSize][1], 12);
  429.         pause = parse(p[PARAM_pause][1], 100);
  430.         rotationfactor = ((double) parse(p[PARAM_rotationfactor][1], 100)) * 0.01;
  431.         parm_radius = parse(p[PARAM_radius][1], -1);
  432.         fontPadding = parse(p[PARAM_fontPadding][1], 0);
  433.         parm_x = parse(p[PARAM_x][1], -1000000);
  434.         parm_y = parse(p[PARAM_y][1], -1000000);
  435.         parm_seed = parse(p[PARAM_seed][1], -1000000);
  436.         
  437.         clockwise = p[PARAM_direction][1].equalsIgnoreCase("CLOCKWISE") ? 
  438.                   true : false ;
  439.         scale = p[PARAM_imageAttribute][1].equalsIgnoreCase("SCALE") ? 
  440.                   true : false ;
  441.         tile = p[PARAM_imageAttribute][1].equalsIgnoreCase("TILE") ? 
  442.                   true : false ;
  443.         center = p[PARAM_imageAttribute][1].equalsIgnoreCase("CENTER") ? 
  444.                   true : false ;
  445.      
  446.         background = getColor(p[PARAM_background][1], Color.black);
  447.         foreground = getColor(p[PARAM_foreground][1], Color.white);
  448.  
  449.  
  450.         try {url = new URL(p[PARAM_url][1]);}
  451.         catch(MalformedURLException e){url = null;}
  452.     }
  453.     
  454.     private int parse(String s, int exp) {
  455.         try {return Integer.parseInt(s);}
  456.         catch(NumberFormatException e){return exp;}
  457.     }
  458.     
  459.     private Color getColor(String s, Color exp) {
  460.         try {
  461.             return new Color(HexToInt(s.substring(0,2)),
  462.                              HexToInt(s.substring(2,4)),
  463.                              HexToInt(s.substring(4)));
  464.         } 
  465.         catch(Exception e){return exp;}
  466.     }
  467.     
  468.     public int HexToInt(String value) {
  469.         int answer = 0;
  470.  
  471.         if(value.substring(0,1).equalsIgnoreCase("a"))
  472.             answer = 160;
  473.         else if(value.substring(0,1).equalsIgnoreCase("b"))
  474.             answer = 176;
  475.         else if(value.substring(0,1).equalsIgnoreCase("c"))
  476.             answer = 192;
  477.         else if(value.substring(0,1).equalsIgnoreCase("d"))
  478.             answer = 208;
  479.         else if(value.substring(0,1).equalsIgnoreCase("e"))
  480.             answer = 224;
  481.         else if(value.substring(0,1).equalsIgnoreCase("f"))
  482.             answer = 240;
  483.         else
  484.             answer = Integer.valueOf(value.substring(0,1)).intValue() * 16;
  485.  
  486.         if(value.substring(1).equalsIgnoreCase("a"))
  487.             answer += 10;
  488.         else if(value.substring(1).equalsIgnoreCase("b"))
  489.             answer += 11;
  490.         else if(value.substring(1).equalsIgnoreCase("c"))
  491.             answer += 12;
  492.         else if(value.substring(1).equalsIgnoreCase("d"))
  493.             answer += 13;
  494.  
  495.         else if(value.substring(1).equalsIgnoreCase("e"))
  496.             answer += 14;
  497.         else if(value.substring(1).equalsIgnoreCase("f"))
  498.             answer += 15;
  499.         else
  500.             answer += Integer.valueOf(value.substring(1)).intValue();
  501.         return answer;
  502.     }
  503. }
  504.  
  505. abstract class Comparer {
  506.     public abstract int compare(Object a, Object b);
  507. }
  508.  
  509. class XComparer extends Comparer {
  510.     public void XComparer() {
  511.     }
  512.     
  513.     public int compare(Object a, Object b) {
  514.         DoublePoint p1 = (DoublePoint) a;
  515.         DoublePoint p2 = (DoublePoint) b;
  516.  
  517.         if(p1.x > p2.x) return +1;
  518.         if(p1.x == p2.x) return 0;
  519.         return -1;
  520.     }
  521. }
  522.  
  523. class YComparer extends Comparer {
  524.     public void YComparer() {
  525.     }
  526.     
  527.     public int compare(Object a, Object b) {
  528.         DoublePoint p1 = (DoublePoint) a;
  529.         DoublePoint p2 = (DoublePoint) b;
  530.  
  531.         if(p1.y > p2.y) return +1;
  532.         if(p1.y == p2.y) return 0;
  533.         return -1;
  534.     }
  535. }
  536.  
  537. class CirclePoints {
  538.     
  539.     private static void sort(Object[] a, Object[] b,
  540.                             int from, int to,
  541.                             boolean up, Comparer c)
  542.     {
  543.         // If there is nothing to sort, return
  544.         if ((a == null) || (a.length < 2)) return;
  545.  
  546.         int i = from, j = to;
  547.         Object center = a[(from + to) / 2];
  548.         do {
  549.             if (up) {  // an ascending sort
  550.                 while((i < to) && (c.compare(center, a[i]) > 0)) i++;
  551.                 while((j > from) && (c.compare(center, a[j]) < 0)) j--;
  552.         } else {   // a descending sort
  553.                 while((i < to) && (c.compare(center, a[i]) < 0)) i++;
  554.                 while((j > from) && (c.compare(center, a[j]) > 0)) j--;
  555.         }
  556.         if (i < j) {
  557.             Object tmp = a[i];  a[i] = a[j];  a[j] = tmp;          // swap elements
  558.             if (b != null) { tmp = b[i]; b[i] = b[j]; b[j] = tmp; }// swap b, too
  559.         }
  560.         if (i <= j) { i++; j--; }
  561.         } while(i <= j);
  562.         if (from < j) sort(a, b, from, j, up, c); // recursively sort the rest
  563.         if (i < to) sort(a, b, i, to, up, c);
  564.     }
  565.  
  566.     public static Vector circle(int xCenter, int yCenter, double radius, int spacing) {
  567.         double xC = (double) xCenter;
  568.         double yC = (double) yCenter;
  569.         double r = radius;
  570.         double s = (double) spacing;
  571.         
  572.         Vector c = new Vector();
  573.         Vector octant[] = new Vector[8];
  574.         for(int i = 0; i < octant.length; i++) {
  575.             octant[i] = new Vector();
  576.         }
  577.  
  578.         /*   1 2
  579.             0   3         (octants 0 - 7)
  580.             7   4
  581.              6 5
  582.         */
  583.  
  584.         double x = 0;
  585.         double y = r;
  586.         double p = s - r;
  587.  
  588.         //plot first set of points
  589.         plotPoints(octant, xC, yC, x, y);
  590.  
  591.         while (x < y) {
  592.             x += spacing;
  593.             if(p < 0) p += 2.00 * x + s;
  594.             else {
  595.                 y -= s;
  596.                 p += 2.00 * (x - y) + s;
  597.             }
  598.             plotPoints(octant, xC, yC, x, y);
  599.         }
  600.  
  601.  
  602.         //sort octants, separately in ascending/descending order
  603.         octant = sort_by_x(octant);
  604.  
  605.         for (int i = 0; i < octant.length; i++)
  606.             for(int j = 0; j < octant[i].size(); j++) 
  607.                 if (!c.contains(octant[i].elementAt(j))) 
  608.                     c.addElement(octant[i].elementAt(j));
  609.         return c;
  610.     }
  611.  
  612.     private static Object[] sort_by_y(Object[] points, int from, int to, int octant) {
  613.         boolean ascending = (octant > 1 && octant < 6) ? true : false;
  614.  
  615.         sort(points, null, from, to, ascending, new YComparer()); 
  616.         return points;
  617.     }
  618.  
  619.     private static Vector[] sort_by_x(Vector[] vectorArray) {
  620.         for (int i = 0; i < 8; i++) {
  621.  
  622.             //first, copy the vector, object by object, into
  623.             // an array of objects
  624.             Object[] points = new DoublePoint[vectorArray[i].size()];
  625.  
  626.             for(int j = 0; j < points.length; j++)
  627.                 points[j] = vectorArray[i].elementAt(j);
  628.  
  629.             //second, sort each octant along the x-axis
  630.             boolean ascending_x = i > 3 ? false : true;
  631.  
  632.             sort(points, null, 0, points.length - 1, ascending_x,
  633.                 new XComparer());
  634.  
  635.             //third, sort each octant along the y-axis
  636.             boolean end_array = false;
  637.             int hold_pos = 0;
  638.             double hold_x = ((DoublePoint)points[0]).x;
  639.             int k = 0;
  640.             while(!end_array){
  641.                 for(k = hold_pos;;k++) {
  642.                     if (k == points.length) {
  643.                         end_array = true;
  644.                         break;
  645.                     }
  646.                     if (((DoublePoint)points[k]).x != hold_x) {
  647.                         points = sort_by_y(points, hold_pos, k - 1, i);
  648.                         hold_x = ((DoublePoint)points[k]).x;
  649.                         hold_pos = k;
  650.                         break;
  651.                     }
  652.                 }
  653.             //sort the last x-grouping
  654.             points = sort_by_y(points, hold_pos, k - 1, i);
  655.             }
  656.  
  657.             //finally, turn the reordered array of objects back into a vector
  658.             Vector v = new Vector();
  659.             for(int j = 0; j < points.length; j++) {
  660.                 v.addElement(points[j]);
  661.             }
  662.             vectorArray[i] = v;
  663.         }
  664.         return vectorArray;
  665.     }
  666.  
  667.     private static void plotPoints(Vector[] v, double xC, double yC, double x, double y){
  668.         v[3].addElement(new DoublePoint(xC + y, yC - x));
  669.         v[0].addElement(new DoublePoint(xC - y, yC - x));
  670.         v[4].addElement(new DoublePoint(xC + y, yC + x));
  671.         v[7].addElement(new DoublePoint(xC - y, yC + x));
  672.         v[2].addElement(new DoublePoint(xC + x, yC - y));
  673.         v[1].addElement(new DoublePoint(xC - x, yC - y));
  674.         v[5].addElement(new DoublePoint(xC + x, yC + y));
  675.         v[6].addElement(new DoublePoint(xC - x, yC + y));
  676.     }
  677. }
  678.  
  679. class DoublePoint {
  680.     public double x;
  681.  
  682.     public double y;
  683.  
  684.     public DoublePoint() {
  685.     this(0.0, 0.0);
  686.     }
  687.  
  688.     public DoublePoint(DoublePoint p) {
  689.     this(p.x, p.y);
  690.     }
  691.  
  692.     public DoublePoint(double x, double y) {
  693.     this.x = x;
  694.     this.y = y;
  695.     }
  696.  
  697.     public DoublePoint getLocation() {
  698.     return new DoublePoint(x, y);
  699.     }
  700.  
  701.     public void setLocation(DoublePoint p) {
  702.     setLocation(p.x, p.y);
  703.     }
  704.  
  705.     public void setLocation(double x, double y) {
  706.     move(x, y);
  707.     }
  708.  
  709.     public void move(double x, double y) {
  710.     this.x = x;
  711.     this.y = y;
  712.     }
  713.  
  714.     public void translate(double x, double y) {
  715.     this.x += x;
  716.     this.y += y;
  717.     }
  718.  
  719.     public boolean equals(Object obj) {
  720.     if (obj instanceof DoublePoint) {
  721.         DoublePoint pt = (DoublePoint)obj;
  722.         return (x == pt.x) && (y == pt.y);
  723.     }
  724.     return false;
  725.     }
  726.  
  727.     public String toString() {
  728.     return getClass().getName() + "[x=" + x + ",y=" + y + "]";
  729.     }
  730. }
  731.  
  732.